#pragma once
#include <iostream>
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
class Connection;
const static int gnum = 64;
// Reactor:
//           1.对于已经就绪的事件，进行通知
//           2.Connection对象的管理工作

//事件派发器
class Reactor
{
public:
Reactor() : _isrunning(false)
    {
    }
    ~Reactor() {}

    void AddConnection(socket_ns::socket_ptr sock, uint32_t events, func_t recver , func_t sender , func_t excepter)
    {
        // 1. 构建Connection对象
        std::shared_ptr<Connection> conn = std::make_shared<Connection>(sock);
        conn->SetEvents(events);
        conn->Register(recver, sender, excepter);
        conn->SetSelf(this);
        // 2. 向内核中设定对fd的关心
        _epoller.AddEvent(conn->Sock()->Sockfd(), conn->Events());
        // 3. 向_connections添加connection对象
        _connections.insert(std::make_pair(sock->Sockfd(), conn));
    }
    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(revs, gnum, timeout);
        for (int i = 0; i < n; ++i)
        {
            int sockfd = revs[i].data.fd;
            uint32_t revents = revs[i].events;
            if (revents & EPOLLHUP)
            {
                // 如果revent对方把链接关了，即EPOLLHUP了，就转化为读写错误
                revents |= (EPOLLIN | EPOLLOUT);
            }
            if (revents & EPOLLERR)
            {
                // 如果revent发生了错误，即EPOLLERR了，就转化为读写错误
                revents |= (EPOLLIN | EPOLLOUT);
            }
            if (revents & EPOLLIN)
            {
                if (_connections.count(sockfd) && _connections[sockfd]->_recver != nullptr)
                    _connections[sockfd]->_recver(_connections[sockfd]);
            }
            if (revents & EPOLLOUT)
            {
                if (_connections.count(sockfd) && _connections[sockfd]->_sender != nullptr)
                    _connections[sockfd]->_recver(_connections[sockfd]);
            }
        }
    }
    // 事件派发核心函数
    void Dispatcher()
    {
        _isrunning = true;
        int timeout = -1;
        while (_isrunning)
        {
            LoopOnce(timeout);
        }
        _isrunning = false;
    }

private:
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    struct epoll_event revs[gnum];
    Epoller _epoller;
    bool _isrunning;
};